﻿unit MemBuffer;

interface

uses
  Winapi.Windows, System.SysUtils, WinSock2Ex, Protocol;

type
  //缓存对象
  TIBuffer = Class
  public
    NextBuffer:       TIBuffer;      (* 指向下一个DIBuffer   *)
    FSocket:          TSocket;        (* Socket               *)
    MapID:            Cardinal;          (* Buffer MapID         *)
    FWSABuf:          WSABUF;         (* WSABuf               *)
    RemoteAddr:       TSockAddr;      (* 远程地址             *)
    RemoteAddrLen:    Integer;        (* 长度                 *)
    UDPAddr:          TSockAddr;      (* UDP                  *)
    UDPAddrLen:       Integer;        (* 长度                 *)
    OverLappedEx:     TOverLappedEx;  (* Overlapped结构扩展   *)
  private
    Size:            Cardinal;          (* Buffer 大小          *)
    Used:            Cardinal;          (* Buffer多少已使用     *)
    SequenceNumber:  WORD;           (* 序列号               *)
    Buffer:          PByte;          (* 缓冲区               *)
  private
    (* 写数据到Buffer               *)
    function AddData(pData: PByte; nSize: Word): Boolean; overload;
    function AddData(data: Cardinal): Boolean; overload;
  public
    (* 数据打包                     *)
    function CreatePackage(sTxt: String): Boolean;  overload;
    function CreatePackage(pData: PByte; nSize: Word): Boolean; overload;
    procedure CreateTestPackage;
    (* 得到Buffer                   *)
    function GetBuffer: PByte;
    (* 获取响应顺序号               *)
    function GetSequenceNumber: WORD;
    (* 设置响应顺序号               *)
    procedure SetSequenceNumber(Value: WORD);
    (* 获取操作类型                 *)
    function GetOperation: IO_POST_EVENT_TYPE;
    (* 设置操作类型                 *)
    procedure SetOperation(IOType: IO_POST_EVENT_TYPE);
    (* 设置回调对象                 *)
    procedure SetCallBackObj(FCallBackObj: Pointer);
    (* 获取回调对象                 *)
    function GetCallBackObj: Pointer;
    (* 设置FWSABuf.buf指向m_pBuffer指针 及FWSABuf.len长度为零       *)
    procedure SetupZeroByteRead;
    (* 设置FWSABuf.buf指向m_pBuffer指针 及FWSABuf.len长度为Used  *)
	  procedure SetupWrite;
    (* 设置FWSABuf.buf指向m_pBuffer指针  *)
	  procedure SetupRead;
    (* 设置FWSABuf.buf指向m_pBuffer指针  *)
    procedure SetupCloseRead;
    (* 设置Buffer使用大小                 *)
    procedure SetUsed(m_iUse: Cardinal);
    (* 得到Buffer使用大小                 *)
    function GetUsed: Cardinal;
    (* 得到Buffer字串                     *)
    function GetBufferString(bHex: Boolean = False): AnsiString;
  public
    (* 初始化DIBuffer                     *)
    procedure InitBuffer;
  public
    constructor Create;
    destructor Destroy; override;
  end;

implementation

constructor TIBuffer.Create;
begin
  inherited Create;
  ZeroMemory(@OverLappedEx.FOverlapped, SizeOf(OverLappedEx.FOverlapped));
  OverLappedEx.FRequest := Self;
  Buffer := HeapAlloc(GetProcessHeap(), $00000008, MAX_PACKAGESIZE);
  InitBuffer;
end;

procedure TIBuffer.InitBuffer;
begin
  FSocket := INVALID_SOCKET;
  NextBuffer := nil;
  Size := 0;
  Used := 0;
  SequenceNumber := 0;
  RemoteAddrLen := SizeOf(RemoteAddr);
  ZeroMemory(@UDPAddr, SizeOf(TSockAddr));
  UDPAddrLen := SizeOf(TSockAddr);
  OverLappedEx.FIOType := IO_INITIALIZE;
  ZeroMemory(@Buffer[0], SizeOf(MAX_PACKAGESIZE));
  //ZeroMemory(Buffer, SizeOf(MAX_PACKAGESIZE));
end;

destructor TIBuffer.Destroy;
begin
  HeapFree(GetProcessHeap(), 0, Buffer);
  inherited Destroy;
end;

function TIBuffer.GetBuffer: PByte;
begin
  //Result := Buffer;
  Result := @Buffer[0];
end;

function TIBuffer.GetSequenceNumber: WORD;
begin
  Result := SequenceNumber;
end;

procedure TIBuffer.SetSequenceNumber(Value: WORD);
begin
  SequenceNumber := Value;
end;

function TIBuffer.GetOperation: IO_POST_EVENT_TYPE;
begin
  Result := OverLappedEx.FIOType;
end;

procedure TIBuffer.SetOperation(IOType: IO_POST_EVENT_TYPE);
begin
  ZeroMemory(@OverLappedEx.FOverlapped, SizeOf(OverLappedEx.FOverlapped));
  OverLappedEx.FIOType := IOType;
end;

procedure TIBuffer.SetCallBackObj(FCallBackObj: Pointer);
begin
  OverLappedEx.FCallBackObj := FCallBackObj;
end;

function TIBuffer.GetCallBackObj: Pointer;
begin
  Result := OverLappedEx.FCallBackObj;
end;

procedure TIBuffer.SetupZeroByteRead;
begin
  FWSABuf.buf := @Buffer[0];
  //FWSABuf.buf := PAnsiChar(Buffer);
  FWSABuf.len := 0;
end;

procedure TIBuffer.SetupWrite;
begin
  FWSABuf.buf := @Buffer[0];
  //FWSABuf.buf := PAnsiChar(Buffer);
  FWSABuf.len := Used;
end;

procedure TIBuffer.SetupRead;
begin
  FWSABuf.buf := @Buffer[0];
  //FWSABuf.buf := PAnsiChar(Buffer);
  FWSABuf.len := MAX_PACKAGESIZE;
  ZeroMemory(@UDPAddr, SizeOf(TSockAddr));
end;

procedure TIBuffer.SetupCloseRead;
begin
  FWSABuf.buf := @Buffer[0];
  //FWSABuf.buf := PAnsiChar(Buffer);
  FWSABuf.len := 0;
end;

procedure TIBuffer.SetUsed(m_iUse: Cardinal);
begin
  Used := m_iUse;
end;

function TIBuffer.GetUsed: Cardinal;
begin
  Result := Used;
end;

function TIBuffer.AddData(pData: PByte; nSize: Word): Boolean;
begin
  if (nSize > MAX_PACKAGESIZE - Used) then
    Result := False
  else
    begin
      CopyMemory(Pointer(Cardinal(GetBuffer) + Used), Pointer(Cardinal(pData)), nSize);
      Used := Used + nSize;
      Result := True;
    end;
end;

function TIBuffer.AddData(data: Cardinal): Boolean;
begin
  Result := AddData(@data, SizeOf(Cardinal));
end;

function TIBuffer.CreatePackage(sTxt: String): Boolean;
var
  nStrLen: Cardinal;
begin
  nStrLen := length(sTxt);
  if (nStrLen < MAX_PACKAGESIZE - 1) and (nStrLen > 0) then
  begin
    AddData(nStrLen);
    AddData(PByte(sTxt), nStrLen);
    Result := True;
    Exit;
  end;
  Result := False;
end;

function TIBuffer.CreatePackage(pData: PByte; nSize: Word): Boolean;
begin
  Result := AddData(pData, nSize);
end;

procedure TIBuffer.CreateTestPackage;
var
  i: Cardinal;
begin
  for i := 0 to MAX_PACKAGESIZE - 1 do
    PByte(Cardinal(Buffer) + i)^ := $68;
  Used := MAX_PACKAGESIZE;
end;

function TIBuffer.GetBufferString(bHex: Boolean): AnsiString;
var
  i: Cardinal;
begin
  for i := 0 to Used - 1 do begin
    if bHex then
      Result := Result + AnsiString(IntToHex(PByte(Cardinal(Buffer) + i)^, 2) + ' ')
    else
      Result := Result + AnsiString(IntToStr(PByte(Cardinal(Buffer) + i)^) + ' ');
  end;
end;

end.
